package com.cxh.androidmedia.render_new.render;

import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import com.cxh.androidmedia.R;
import com.cxh.androidmedia.base.AMApp;
import com.cxh.androidmedia.render_old.bean.BitmapTexture;
import com.cxh.androidmedia.render_old.bean.GLPoint2;
import com.cxh.androidmedia.render_old.bean.GLPoint3;
import com.cxh.androidmedia.render_old.bean.GLTriangle2;
import com.cxh.androidmedia.render_old.bean.GLTriangle3;
import com.cxh.androidmedia.utils.CCLog;
import com.cxh.androidmedia.utils.OpenGLUtils;

import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 *  绘制一个地球
 */
public class LightLearnRender implements GLSurfaceView.Renderer {

    private static final String VERTEX_SHADER = "" +
            "attribute vec4 vPosition; \n" +
            "attribute vec2 aTextureCoord; \n" +
            "uniform mat4 mPMatrix; \n" +
            "uniform mat4 mVMatrix; \n" +
            "uniform mat4 mMMatrix; \n" +
            "varying vec2 vTexCoord; \n" +
            "void main(){ \n" +
            "gl_Position = mPMatrix * mVMatrix * mMMatrix * vPosition; \n" +
            "vTexCoord = aTextureCoord; \n" +
            "}";
    private static final String FRAGMENT_SHADER = "" +
            "precision highp float; \n" +
            "uniform sampler2D uTextureUnit; \n" +
            "varying vec2 vTexCoord; \n" +
            "void main(){ " +
            "gl_FragColor = texture2D(uTextureUnit,vTexCoord); \n" +
//            "gl_FragColor = vec4(1f, 1f,1f, 1f); " +
            "}";

    private final float mRadius = 0.8f;
    private final int mBlockCount = 360;

    // 地球坐标和纹理映射坐标
    private float[] mVertexArray;
    private float[] mTextureArray;
    // 矩阵MVP
    private float[] mPMatrix = new float[16];
    private float[] mVMatrix = new float[16];
    private float[] mMMatrix = new float[16];

    //  shader参数
    private int mGLProgram;
    private int mPositionHandler;
    private int mTextureHandler;
    private BitmapTexture mBitmapTexture;

    // 使用vbo，（小米8）一帧耗时约最高2毫秒，效果明显
    private int[] vertexVbo;
    private int[] textureVbo;

    // 地球自转
    private float mSelfAngle;
    private float mAngle = -20f;
    private float mNear = 0.1f;
    private float mFar = 0.1f;


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES30.glClearColor(0f, 0f, 0f, 0f);
        GLES30.glEnable(GLES30.GL_DEPTH_TEST);

        initGlSLParams();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0, width, height);
        // 主要还是长宽进行比例缩放
        float aspectRatio = (float) height / (float) width;
        // 设置相机
        Matrix.setLookAtM(mVMatrix, 0, 0, 0, 2f, 0, 0, 0, 0, 1f, 0f);
        // 透视投影
        // Matrix.frustumM(mPMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, 1f, 3f);
        // 正交投影
        Matrix.orthoM(mPMatrix, 0, -1f, 1f, -aspectRatio, aspectRatio, 1f, 10f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES30.glUseProgram(mGLProgram);
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);

        // 将程序添加到OpenGL ES环境
        GLES30.glUseProgram(mGLProgram);
        // 设置变换矩阵
        updateMatrixData();
        OpenGLUtils.setUniformMatrix4fv(mGLProgram, "mPMatrix", mPMatrix);
        OpenGLUtils.setUniformMatrix4fv(mGLProgram, "mVMatrix", mVMatrix);
        OpenGLUtils.setUniformMatrix4fv(mGLProgram, "mMMatrix", mMMatrix);

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vertexVbo[0]);
        GLES30.glEnableVertexAttribArray(mPositionHandler);
        GLES30.glVertexAttribPointer(mPositionHandler, 3, GLES30.GL_FLOAT, false, 0, 0);
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, textureVbo[0]);
        GLES30.glEnableVertexAttribArray(mTextureHandler);
        GLES30.glVertexAttribPointer(mTextureHandler, 2, GLES30.GL_FLOAT, false, 0, 0);
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

        // 激活纹理
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        // 绑定纹理
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mBitmapTexture.mTextureId);
        // 绘制三角形
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mVertexArray.length / 3);

        GLES30.glDisableVertexAttribArray(mPositionHandler);
        GLES30.glDisableVertexAttribArray(mTextureHandler);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
    }


    private void initGlSLParams() {
        mGLProgram = OpenGLUtils.loadProgram(VERTEX_SHADER, FRAGMENT_SHADER);
        mPositionHandler = GLES30.glGetAttribLocation(mGLProgram, "vPosition");
        mTextureHandler = GLES30.glGetAttribLocation(mGLProgram, "aTextureCoord");
        mBitmapTexture = OpenGLUtils.loadTexture(AMApp.get(), R.drawable.earth);

        initPositionAndTexture();

        // 顶点缓冲，只会拷贝一次顶点数据（CPU -> GPU）
        vertexVbo = OpenGLUtils.initVbo(mVertexArray);
        textureVbo = OpenGLUtils.initVbo(mTextureArray);
    }

    private void updateMatrixData() {
        mSelfAngle += 0.2f;
        if (mSelfAngle <= 0) {
            mSelfAngle = 360f;
        }

        // 地球最大斜率23.5，这时候中国是夏天，北极出现极昼
        Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1);
        Matrix.rotateM(mMMatrix, 0, mSelfAngle, 0, 1, 0);
    }

    /**
     *  地球球面坐标怕，以及纹理映射坐标
     */
    private void initPositionAndTexture() {
        List<GLTriangle3> triangles = new ArrayList<>();
        List<GLTriangle2> textureArray = new ArrayList<>();

        // 每个方块的角度（纬度）
        float minAngle = 360f / mBlockCount;
        // 纬度只需要遍历180度，经度需要遍历360度
        int mLatitudeCount = mBlockCount / 2;
        // 纹理的最小渲染尺寸
        float minTextureBlockX = 1f / mBlockCount;
        float minTextureBlockY = 1f / mLatitudeCount;

        for (int i = 0; i < mLatitudeCount; i++) {
            float angleLatitude = minAngle * i;
            float angleLatitudeNext = minAngle * (i + 1);
            float texBlockY = minTextureBlockY * i;
            float texBlockYNext = minTextureBlockY * (i + 1);
            if (0 == i) {
                // 北极圈
                for (int j = 0; j < mBlockCount; j++) {
                    float angleLongitude = minAngle * j;
                    float angleLongitudeNext = minAngle * (j + 1);
                    float texBlockX = minTextureBlockX * j;
                    float texBlockXNext = minTextureBlockX * (j + 1);
                    // 构成北极圈的三角形顶点
                    GLPoint3 northPole = new GLPoint3(0f, 1f, 0f);
                    GLPoint3 leftPoint = new GLPoint3(angleLongitude, angleLatitudeNext);
                    GLPoint3 rightPoint = new GLPoint3(angleLongitudeNext, angleLatitudeNext);
                    GLTriangle3 triangle3 = new GLTriangle3(northPole, leftPoint, rightPoint);
                    triangles.add(triangle3);

                    // 采样区域坐标
                    GLPoint2 northPoleBlock = new GLPoint2(texBlockX, texBlockY);
                    GLPoint2 leftPointBlock = new GLPoint2(texBlockX, texBlockYNext);
                    GLPoint2 rightPointBlock = new GLPoint2(texBlockXNext, texBlockYNext);
                    GLTriangle2 triangle2 = new GLTriangle2(northPoleBlock, leftPointBlock, rightPointBlock);
                    textureArray.add(triangle2);

                }

            } else if (i == (mLatitudeCount - 1)) {
                // 南极圈
                for (int j = 0; j < mBlockCount; j++) {
                    float angleLongitude = minAngle * j;
                    float angleLongitudeNext = minAngle * (j + 1);
                    float texBlockX = minTextureBlockX * j;
                    float texBlockXNext = minTextureBlockX * (j + 1);
                    // 构成南极圈的三角形顶点
                    GLPoint3 northPole = new GLPoint3(0f, -1f, 0f);
                    GLPoint3 leftPoint = new GLPoint3(angleLongitude, angleLatitude);
                    GLPoint3 rightPoint = new GLPoint3(angleLongitudeNext, angleLatitude);
                    GLTriangle3 triangle3 = new GLTriangle3(leftPoint, rightPoint, northPole);
                    triangles.add(triangle3);

                    // 采样区域坐标
                    GLPoint2 northPoleBlock = new GLPoint2(texBlockX, texBlockY);
                    GLPoint2 leftPointBlock = new GLPoint2(texBlockX, texBlockYNext);
                    GLPoint2 rightPointBlock = new GLPoint2(texBlockXNext, texBlockYNext);
                    GLTriangle2 triangle2 = new GLTriangle2(leftPointBlock, rightPointBlock, northPoleBlock);
                    textureArray.add(triangle2);

                }

            } else {
                // 其余全是四边形（俩三角形）
                for (int j = 0; j < mBlockCount; j++) {
                    float angleLongitude = minAngle * j;
                    float angleLongitudeNext = minAngle * (j + 1);
                    float texBlockX = minTextureBlockX * j;
                    float texBlockXNext = minTextureBlockX * (j + 1);
                    // 四个顶点
                    GLPoint3 leftTopPoint3 = new GLPoint3(angleLongitude, angleLatitude);
                    GLPoint3 leftBottomPoint3 = new GLPoint3(angleLongitude, angleLatitudeNext);
                    GLPoint3 rightTopPoint3 = new GLPoint3(angleLongitudeNext, angleLatitude);
                    GLPoint3 rightBottomPoint3 = new GLPoint3(angleLongitudeNext, angleLatitudeNext);

                    GLTriangle3 triangle3Left = new GLTriangle3(leftTopPoint3, leftBottomPoint3, rightBottomPoint3);
                    GLTriangle3 triangle3Right = new GLTriangle3(leftTopPoint3, rightBottomPoint3, rightTopPoint3);
                    triangles.add(triangle3Left);
                    triangles.add(triangle3Right);

                    // 采样区域
                    GLPoint2 leftTopBlock = new GLPoint2(texBlockX, texBlockY);
                    GLPoint2 leftBottomBlock = new GLPoint2(texBlockX, texBlockYNext);
                    GLPoint2 rightTopBlock = new GLPoint2(texBlockXNext, texBlockY);
                    GLPoint2 rightBottomBlock = new GLPoint2(texBlockXNext, texBlockYNext);
                    GLTriangle2 triangle2Left = new GLTriangle2(leftTopBlock, leftBottomBlock, rightBottomBlock);
                    GLTriangle2 triangle2Right = new GLTriangle2(leftTopBlock, rightBottomBlock, rightTopBlock);
                    textureArray.add(triangle2Left);
                    textureArray.add(triangle2Right);
                }
            }
        }

        // 将对象转为顶点数组(3个点 * 3个轴xyz、纹理是UV两个轴)
        mVertexArray = new float[triangles.size() * 9];
        mTextureArray = new float[textureArray.size() * 6];
        CCLog.i("vertex count : " + mVertexArray.length);
        for (int i = 0; i < triangles.size(); i++) {
            GLTriangle3 triangle3 = triangles.get(i);
            GLTriangle2 triangle2 = textureArray.get(i);
            int startIndexVertex = i * 9;
            int startIndexTexture = i * 6;
            mVertexArray[startIndexVertex] = (float) (triangle3.A.x * mRadius);
            mVertexArray[startIndexVertex + 1] = (float) (triangle3.A.y * mRadius);
            mVertexArray[startIndexVertex + 2] = (float) (triangle3.A.z * mRadius);
            mVertexArray[startIndexVertex + 3] = (float) (triangle3.B.x * mRadius);
            mVertexArray[startIndexVertex + 4] = (float) (triangle3.B.y * mRadius);
            mVertexArray[startIndexVertex + 5] = (float) (triangle3.B.z * mRadius);
            mVertexArray[startIndexVertex + 6] = (float) (triangle3.C.x * mRadius);
            mVertexArray[startIndexVertex + 7] = (float) (triangle3.C.y * mRadius);
            mVertexArray[startIndexVertex + 8] = (float) (triangle3.C.z * mRadius);

            mTextureArray[startIndexTexture] = triangle2.A.x;
            mTextureArray[startIndexTexture + 1] = triangle2.A.y;
            mTextureArray[startIndexTexture + 2] = triangle2.B.x;
            mTextureArray[startIndexTexture + 3] = triangle2.B.y;
            mTextureArray[startIndexTexture + 4] = triangle2.C.x;
            mTextureArray[startIndexTexture + 5] = triangle2.C.y;
        }
    }
}
